// usb.h

#include <objbase.h>
#include <winioctl.h>

// =========================================================================
// Standard device request constants:
//
// 1) USB_REQUEST_GET_STATUS
//
// Get status information. Used in any context.
//
// 2) USB_REQUEST_CLEAR_FEATURE
//
// Clears a two-state feature. Used in any context.
//
// 3) USB_REQUEST_SET_FEATURE
//
// Sets a two-state feature. Used in any context.
//
// 4) USB_REQUEST_SET_ADDRESS
//
// Sets device address. Used with devices.
//
// 5) USB_REQUEST_GET_DESCRIPTOR
//
// Gets device, configuration, or string descriptor. Used with devices.
//
// 6) USB_REQUEST_SET_DESCRIPTOR
//
// Sets a descriptor (optional). Used with devices.
//
// 7) USB_REQUEST_GET_CONFIGURATION
//
// Gets current configuration index. Used with devices.
//
// 8) USB_REQUEST_SET_CONFIGURATION
//
// Sets new current configuration. Used with devices.
//
// 9) USB_REQUEST_GET_INTERFACE
//
// Gets current alternate setting index. Used with interfaces.
//
// 10) USB_REQUEST_SET_INTERFACE
//
// Enables alternate setting. Used with interfaces.
//
// 11) USB_REQUEST_SYNCH_FRAME
//
// Reports synchronization frame number. Used with isochronous endpoints.
//
// NOTE: I only use USB_REQUEST_GET_DESCRIPTOR, and then only in the context
// of the DeviceIoControl() IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
// control code.
// =========================================================================

#define USB_REQUEST_GET_STATUS        0x00
#define USB_REQUEST_CLEAR_FEATURE     0x01
#define USB_REQUEST_SET_FEATURE       0x03
#define USB_REQUEST_SET_ADDRESS       0x05
#define USB_REQUEST_GET_DESCRIPTOR    0x06
#define USB_REQUEST_SET_DESCRIPTOR    0x07
#define USB_REQUEST_GET_CONFIGURATION 0x08
#define USB_REQUEST_SET_CONFIGURATION 0x09
#define USB_REQUEST_GET_INTERFACE     0x0A
#define USB_REQUEST_SET_INTERFACE     0x0B
#define USB_REQUEST_SYNC_FRAME        0x0C

// =========================================================================
// Descriptor types
//
// NOTE: I only use USB_STRING_DESCRIPTOR_TYPE, and then only in the context
// of the DeviceIoControl() IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION
// control code.
// =========================================================================

#define USB_DEVICE_DESCRIPTOR_TYPE          0x01
#define USB_CONFIGURATION_DESCRIPTOR_TYPE   0x02
#define USB_STRING_DESCRIPTOR_TYPE          0x03
#define USB_INTERFACE_DESCRIPTOR_TYPE       0x04
#define USB_ENDPOINT_DESCRIPTOR_TYPE        0x05

// ===============================
// DeviceIoControl() control codes
// ===============================

// Non-host controller-specific function codes

#define USB_GET_NODE_INFORMATION                    258
#define USB_GET_NODE_CONNECTION_INFORMATION         259
#define USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION     260
#define USB_GET_NODE_CONNECTION_NAME                261

// Host controller-specific function codes

#define HCD_GET_ROOT_HUB_NAME  258
#define HCD_GET_DRIVERKEY_NAME 265

// Device type

#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN

// DeviceIoControl() control codes

#define IOCTL_GET_HCD_DRIVERKEY_NAME \
        CTL_CODE(FILE_DEVICE_USB, \
                 HCD_GET_DRIVERKEY_NAME, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

#define IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION \
        CTL_CODE(FILE_DEVICE_USB, \
                 USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION \
        CTL_CODE(FILE_DEVICE_USB, \
                 USB_GET_NODE_CONNECTION_INFORMATION, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

#define IOCTL_USB_GET_NODE_CONNECTION_NAME \
        CTL_CODE(FILE_DEVICE_USB, \
                 USB_GET_NODE_CONNECTION_NAME, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

#define IOCTL_USB_GET_NODE_INFORMATION \
        CTL_CODE(FILE_DEVICE_USB, \
                 USB_GET_NODE_INFORMATION, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

#define IOCTL_USB_GET_ROOT_HUB_NAME \
        CTL_CODE(FILE_DEVICE_USB, \
                 HCD_GET_ROOT_HUB_NAME, \
                 METHOD_BUFFERED, \
                 FILE_ANY_ACCESS)

// USB structures.
//
// NOTE: I only work directly with the USB_DESCRIPTOR_REQUEST,
// USB_NODE_CONNECTION_INFORMATION, and USB_NODE_INFORMATION structures. The
// USB_NODE_CONNECTION_INFORMATION and USB_NODE_INFORMATION structures refer
// to other structures. Any structures not used are present for information
// purposes.
//
// NOTE: Borland C++ 5.5.1 uses #include <pshpack1.h> to align structure
// fields on 1-byte boundaries. Furthermore, #include <poppack.h> is used to
// revert to previous structure alignment.

#include <pshpack1.h>

typedef struct _USB_DEVICE_DESCRIPTOR
{
   UCHAR bLength;
   UCHAR bDescriptorType; // 1
   USHORT bcdUSB;         // USB version number in binary-coded decimal format
   UCHAR bDeviceClass;    // device class code (e.g., 1 for audio)
   UCHAR bDeviceSubClass; // device subclass code (e.g., audio class has
                          // subclass codes for control, streaming, and so on)
   UCHAR bDeviceProtocol; // mass storage device class has protocol codes for
                          // different ways to use endpoints for data transfer
   UCHAR bMaxPacketSize0; // maximum size of data packet for control transfer
                          // over endpoint 0
   USHORT idVendor;       // vendor code for device
   USHORT idProduct;      // vendor-specific product code for device
   USHORT bcdDevice;      // device's release number (in binary-coded decimal)
   UCHAR iManufacturer;   // index of manufacturer string descriptor
   UCHAR iProduct;        // index of product string descriptor
   UCHAR iSerialNumber;   // index of serial number string descriptor 
   UCHAR bNumConfigurations; // number of configurations supported by device
}
USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;

typedef struct _USB_CONFIGURATION_DESCRIPTOR
{
   UCHAR bLength;
   UCHAR bDescriptorType; // 2
   USHORT wTotallength;   // total length of configuration descriptor plus the
                          // interface and endpoint descriptors that belong to
                          // the configuration
   UCHAR bNumInterfaces;  // number of interfaces belonging to configuration
                          // (alternate settings not included in this count)
   UCHAR bConfigurationValue; // configuration identifier index
   UCHAR iConfiguration;  // optional string descriptor index describing the
                          // configuration
   UCHAR bmAttributes;    // bitmask describing power and other
                          // characteristics of this configuration
   UCHAR MaxPower;        // maximum number of 2-milliamp power units device
                          // draws from the bus
}
USB_CONFIGURATION_DESCRIPTOR, *PUSB_CONFIGURATION_DESCRIPTOR;

typedef struct _USB_INTERFACE_DESCRIPTOR
{
   UCHAR bLength;
   UCHAR bDescriptorType;    // 4
   UCHAR bInterfaceNumber;   // index value used in a SET_INTERFACE control
                             // transaction to specify interface activation
   UCHAR bAlternateSetting;  // index value used in a SET_INTERFACE control
                             // transaction to specify interface activation
   UCHAR bNumEndpoints;      // number of endpoints (apart from endpoint 0)
                             // belonging to interface
   UCHAR bInterfaceClass;    // device descriptors often place 0 in the 
   UCHAR bInterfaceSubClass; // bDeviceClass, bDeviceSubClass, and 
   UCHAR bInterfaceProtocol; // bDeviceProtocol fields -- the actual codes
                             // appear in these fields
   UCHAR iInterface;         // index of string descriptor describing this
                             // interface
}
USB_INTERFACE_DESCRIPTOR, *PUSB_INTERFACE_DESCRIPTOR;

typedef struct _USB_ENDPOINT_DESCRIPTOR
{
   UCHAR bLength;
   UCHAR bDescriptorType;  // 5
   UCHAR bEndpointAddress; // the endpoint's directionality and number
   UCHAR bmAttributes;     // endpoint type in bits 0-1 (e.g., control is 00)
   USHORT wMaxPacketSize;  // maximum amount of data this endpoint can
                           // transfer in one transaction
   UCHAR bInterval;        // polling interval -- how often the host should
                           // poll the endpoint for a possible data transfer
}
USB_ENDPOINT_DESCRIPTOR, *PUSB_ENDPOINT_DESCRIPTOR;

typedef struct _USB_STRING_DESCRIPTOR
{
   UCHAR bLength;         // length of string data
   UCHAR bDescriptorType; // 3
   WCHAR bString[1];      // string data in Unicode format
}
USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;

// NOTE: String #0 is an array of supported language identifiers instead of a
// character string (e.g., 0x0409, American English)

typedef enum _USB_CONNECTION_STATUS
{
   NoDeviceConnected,
   DeviceConnected,
   DeviceFailedEnumeration,
   DeviceGeneralFailure,
   DeviceCausedOvercurrent,
   DeviceNotEnoughPower,
   DeviceNotEnoughBandwidth,
   DeviceHubNestedTooDeeply,
   DeviceInLegacyHub
}
USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;

typedef struct _USB_PIPE_INFO
{
   USB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
   ULONG ScheduleOffset;
}
USB_PIPE_INFO, *PUSB_PIPE_INFO;

typedef struct _USB_NODE_CONNECTION_INFORMATION
{
   ULONG ConnectionIndex;
   USB_DEVICE_DESCRIPTOR DeviceDescriptor;
   UCHAR CurrentConfigurationValue;
   BOOLEAN LowSpeed;
   BOOLEAN DeviceIsHub;
   USHORT DeviceAddress;
   ULONG NumberOfOpenPipes;
   USB_CONNECTION_STATUS ConnectionStatus;
   USB_PIPE_INFO PipeList [32];
}
USB_NODE_CONNECTION_INFORMATION, *PUSB_NODE_CONNECTION_INFORMATION;

typedef enum _USB_HUB_NODE
{
   UsbHub,
   UsbMIParent
}
USB_HUB_NODE;

typedef struct _USB_HUB_DESCRIPTOR
{
   UCHAR bDescriptorLength;
   UCHAR bDescriptorType;
   UCHAR bNumberOfPorts;
   USHORT wHubCharacteristics;
   UCHAR bPowerOnToPowerGood;
   UCHAR bHubControlCurrent;
   UCHAR bRemoveAndPowerMask [64];       
}
USB_HUB_DESCRIPTOR, *PUSB_HUB_DESCRIPTOR;

typedef struct _USB_HUB_INFORMATION
{
   USB_HUB_DESCRIPTOR HubDescriptor;

   BOOLEAN HubIsBusPowered;
}
USB_HUB_INFORMATION, *PUSB_HUB_INFORMATION;

typedef struct _USB_MI_PARENT_INFORMATION
{
   ULONG NumberOfInterfaces;
}
USB_MI_PARENT_INFORMATION, *PUSB_MI_PARENT_INFORMATION;

typedef struct _USB_NODE_INFORMATION
{
   USB_HUB_NODE NodeType;
   union
   {
       USB_HUB_INFORMATION HubInformation;
       USB_MI_PARENT_INFORMATION MiParentInformation;
   }
   u;
}
USB_NODE_INFORMATION, *PUSB_NODE_INFORMATION;

typedef struct _USB_DESCRIPTOR_REQUEST
{
   ULONG ConnectionIndex;
   struct
   {
      UCHAR bmRequest;
      UCHAR bRequest;
      USHORT wValue;
      USHORT wIndex;
      USHORT wLength;
   }
   SetupPacket;
   UCHAR Data [2048];
}
USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;

#include <poppack.h>
